package com.xmim.server;

import com.xmim.core.constants.MessageConstants;
import com.xmim.core.container.AbstractServerContainer;
import com.xmim.core.container.Container;
import com.xmim.core.container.ServerContainer;
import com.xmim.core.exception.ContainerException;
import com.xmim.fulcrum.FulcrumConfig;
import com.xmim.fulcrum.FulcrumFactory;
import com.xmim.server.examples.NettyChannelInitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.net.BindException;
import java.util.Map;


@Slf4j
public class NettyServer extends AbstractServerContainer<String, ChannelHandler> {

    // 接收连接
    private EventLoopGroup boss;
    //处理连接
    private EventLoopGroup worder;
    // 启动引导器
    private ServerBootstrap bootstrap;
    private boolean isInit;


    public NettyServer(FulcrumFactory factory, ServerContainer parent) {
        super(factory, parent);
    }


    @Override
    protected void onInit() {
        this.bootstrap = new ServerBootstrap();
        this.boss = new NioEventLoopGroup();
        this.worder = new NioEventLoopGroup();
        //1 设置reactor 线程
        this.bootstrap.group(this.boss, this.worder);
        //2 设置nio类型的channel
        this.bootstrap.channel(NioServerSocketChannel.class);
        //3 设置通道选项
        this.bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
        //4 装配流水线
        this.bootstrap.childHandler(new NettyChannelInitializer(this.getFactory(), this.handlers));
    }


    @Override
    protected void onBind() throws ContainerException {  // 5 开始绑定server
        //开始启动/连接失败尝试一个新的端口
        FulcrumConfig config = getFactory().getConfig();
        ChannelFuture channelFuture = null;
        boolean isStart = false;
        while (!isStart) {
            try {
                channelFuture = bootstrap.bind(config.getHost(), config.getPort()).sync();
                log.info("XMIM服务启动, 主机：{}  端口为：{} ", config.getHost(), config.getPort());
                isStart = true;
            } catch (Exception e) {
                if (e instanceof BindException) {
                    log.error("XMIM服务启动异常--尝试一个新的端口");
                    config.setPort(config.getPort() + 1);
                } else {
                    log.error("XMIM服务启动异常--", e);
                    throw new ContainerException("XMIM服务启动异常", e);
                }
            }
            //等待一秒钟再重试
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new ContainerException(e);
            }
        }
        try {
            // 6 监听通道关闭事件
            // 应用程序会一直等待，直到channel关闭
            ChannelFuture closeFuture = channelFuture.channel().closeFuture();
            closeFuture.sync();
        } catch (Exception e) {
            log.error("XMIM服务发生其他异常", e);
            throw new ContainerException(e);
        }
    }


    @Override
    protected void onClose() throws ContainerException {
        try {
            worder.shutdownGracefully();
            boss.shutdownGracefully();
        } catch (Exception e) {
            throw new ContainerException(e);
        }
    }


    @Override
    public boolean checkHandler(Class<?> handler) {
        return ChannelHandler.class.isAssignableFrom(handler);
    }

    @Override
    public FulcrumFactory getFactory() {
        return (FulcrumFactory) super.getFactory();
    }
}
